package com.zj.blockchain.service;

import com.alibaba.fastjson.JSON;
import com.zj.blockchain.constant.BlockConstant;
import com.zj.blockchain.model.Block;
import com.zj.blockchain.model.Message;
import com.zj.blockchain.model.Transaction;
import com.zj.blockchain.util.BlockCache;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @className: PowService
 * @description: 共识机制 采用POW即工作量证明实现共识
 * @author: allnas
 * @date: 2020/2/29
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PowService {

    private final BlockService blockService;

    private final BlockCache blockCache;

    private final P2pService p2pService;

    /**
     * 通过“挖矿”进行工作量证明，实现节点间的共识
     *
     * @return
     */
    public Block mine() {
        List<Transaction> tsaList = new ArrayList<Transaction>();
        Transaction tsa1 = new Transaction();
        tsa1.setId(10);
        tsa1.setInfo("共识机制生成的区块");
        tsaList.add(tsa1);
        Transaction tsa2 = new Transaction();
        tsa2.setId(11);
        tsa2.setInfo("区块链高度为：" + (blockCache.getLatestBlock().getIndex() + 1));
        tsaList.add(tsa2);

        String newBlockHash = "";
        int nonce = 0;
        long start = System.currentTimeMillis();
        log.info("开始挖矿");

        while (true) {
            // 计算新区块hash值
            newBlockHash = blockService.calculateHash(blockCache.getLatestBlock().getHash(), tsaList, nonce);
            // 校验hash值
            if (blockService.isValidHash(newBlockHash)) {
                log.info("挖矿完成，正确的hash值：" + newBlockHash);
                log.info("挖矿耗费时间：" + (System.currentTimeMillis() - start) + "ms");
                break;
            }
            log.info("第" + (nonce + 1) + "次尝试计算的hash值：" + newBlockHash);
            nonce++;
        }

        // 创建新的区块
        Block block = blockService.createNewBlock(nonce, blockCache.getLatestBlock().getHash(), newBlockHash, tsaList);

        //创建成功后，全网广播出去
        Message msg = new Message();
        msg.setType(BlockConstant.RESPONSE_LATEST_BLOCK);
        msg.setData(JSON.toJSONString(block));
        p2pService.broadcast(JSON.toJSONString(msg));

        return block;
    }
}
